﻿#region License statement
// NJamb, a specification and delta-specification DSL
// Copyright (c) 2010-2011, Mark Knell
// Published under the MIT License; all other rights reserved
#endregion

#region using...
using System;
using System.Collections.Generic;
using NJamb.Parser.SpecificationBuilders.SubjectHas.AbstractEnumerable;
using NJamb.Specifications;
using Stile.Readability;
#endregion

namespace NJamb.Parser.SpecificationBuilders.SubjectHas.Simple.Enumerable.Quantifiers
{
    public static class EnumerableQuantifiedHasExtensions
    {
        public static IEnumerableQuantifiedHas<TItem, TSpecifies> AtLeast<TSubject, TItem, TSpecifies>(
            this IEnumerableHas<TSubject, TItem, TSpecifies> has, int inclusiveMin) where TSubject : class, IEnumerable<TItem>
            where TSpecifies : class, ISpecification
        {
            return new Quantifier<TSubject, TItem, TSpecifies>(has.Xray.SpecificationBuilder,
                inclusiveMin,
                x => x >= inclusiveMin,
                "at least " + inclusiveMin.ToDebugString());
        }

        public static IEnumerableQuantifiedHas<TItem, TSpecifies> AtMost<TSubject, TItem, TSpecifies>(
            this IEnumerableHas<TSubject, TItem, TSpecifies> has, int inclusiveMax) where TSubject : class, IEnumerable<TItem>
            where TSpecifies : class, ISpecification
        {
            return new Quantifier<TSubject, TItem, TSpecifies>(has.Xray.SpecificationBuilder,
                inclusiveMax,
                x => x <= inclusiveMax,
                "at most " + inclusiveMax.ToDebugString());
        }

        public static IEnumerableQuantifiedHas<TItem, TSpecifies> Exactly<TSubject, TItem, TSpecifies>(
            this IEnumerableHas<TSubject, TItem, TSpecifies> has, int count) where TSubject : class, IEnumerable<TItem>
            where TSpecifies : class, ISpecification
        {
            return new Quantifier<TSubject, TItem, TSpecifies>(has.Xray.SpecificationBuilder,
                count,
                x => x == count,
                "exactly " + count.ToDebugString());
        }

        public static IEnumerableQuantifiedHas<TItem, TSpecifies> FewerThan<TSubject, TItem, TSpecifies>(
            this IEnumerableHas<TSubject, TItem, TSpecifies> has, int noninclusiveMax) where TSubject : class, IEnumerable<TItem>
            where TSpecifies : class, ISpecification
        {
            return new Quantifier<TSubject, TItem, TSpecifies>(has.Xray.SpecificationBuilder,
                noninclusiveMax,
                x => x < noninclusiveMax,
                "fewer than " + noninclusiveMax.ToDebugString());
        }

        public static IEnumerableQuantifiedHas<TItem, TSpecifies> MoreThan<TSubject, TItem, TSpecifies>(
            this IEnumerableHas<TSubject, TItem, TSpecifies> has, int noninclusiveMin) where TSubject : class, IEnumerable<TItem>
            where TSpecifies : class, ISpecification
        {
            return new Quantifier<TSubject, TItem, TSpecifies>(has.Xray.SpecificationBuilder,
                noninclusiveMin,
                x => x > noninclusiveMin,
                "more than " + noninclusiveMin.ToDebugString());
        }

        public class Quantifier<TSubject, TItem, TSpecifies> : EnumerableQuantifiedHas<TSubject, TItem, TSpecifies>
            where TSubject : class, IEnumerable<TItem>
            where TSpecifies : class, ISpecification
        {
            private readonly int _count;
            private readonly Func<int, bool> _countPredicate;
            private readonly string _qualifier;

            public Quantifier(ICollaboratingSpecificationBuilder<TSubject, TSpecifies> specificationBuilder,
                int count,
                Func<int, bool> countPredicate,
                string qualifier)
                : base(specificationBuilder)
            {
                _count = count;
                _countPredicate = countPredicate;
                _qualifier = qualifier;
            }

            protected override int Count
            {
                get { return _count; }
            }
            protected override Func<int, bool> CountPredicate
            {
                get { return _countPredicate; }
            }
            protected override string Qualifier
            {
                get { return _qualifier; }
            }
        }
    }
}
